#include "utils.h"

// base64转码
std::string Utils::Base64Encode(const char *buffer, int length, bool newLine)
{
	BIO *bmem = NULL;
	BIO *b64 = NULL;
	BUF_MEM *bptr;

	b64 = BIO_new(BIO_f_base64());
	if (!newLine) {
		BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	}
	bmem = BIO_new(BIO_s_mem());
	b64 = BIO_push(b64, bmem);
	BIO_write(b64, buffer, length);
	BIO_flush(b64);
	BIO_get_mem_ptr(b64, &bptr);
	BIO_set_close(b64, BIO_NOCLOSE);

	std::string result;
	result.assign(bptr->data, bptr->length);

	BIO_free_all(b64);

	return result;
}

// base64 解码
std::string Utils::Base64Decode(const char *input, int length, bool newLine)
{
	BIO *b64 = NULL;
	BIO *bmem = NULL;
	b64 = BIO_new(BIO_f_base64());
	if (!newLine) {
		BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	}
	bmem = BIO_new_mem_buf((void*)input, length);
	b64 = BIO_push(b64, bmem);
	std::string result;
	result.resize(length);

	int size = BIO_read(b64, (void *)result.data(), length);
	result.resize(size);

	BIO_free_all(b64);

	return result;
}

//AES加密pkcs#5填充
bool Utils::AESEncrypt(const char* pszKey, const char* buffer, size_t length, std::string* res)
{
	unsigned char keyBuf[AES_KEY_LENGTH];
	unsigned char iv[AES_KEY_LENGTH] = { 10, 4, 117, 110, 100, 11, 5, 11, 7, 36, 98, 25, 15, 11, 7, 10 };
	//unsigned char iv[AES_KEY_LENGTH] = { 0 };

	AES_KEY aesKey;
	int ret;

	unsigned int uiPaddingLen;
	unsigned int uiTotalLen;
	unsigned char* pData;

	memcpy(keyBuf, pszKey, AES_KEY_LENGTH);

	ret = AES_set_encrypt_key(keyBuf, 128, &aesKey);
	if (ret != 0) return false;

	uiPaddingLen = AES_KEY_LENGTH - (length % AES_KEY_LENGTH);
	uiTotalLen = length + uiPaddingLen;
	pData = (unsigned char*)malloc(uiTotalLen);
	memcpy(pData, buffer, length);

	if (uiPaddingLen > 0) memset(pData + length, uiPaddingLen, uiPaddingLen);

	res->clear();
	res->resize(uiTotalLen);

	AES_cbc_encrypt(pData, (unsigned char*)res->data(), uiTotalLen, &aesKey, iv, AES_ENCRYPT);

	free(pData);
	return true;
}


bool Utils::AESEncrypt_2(unsigned char cKeyArr[16], const char* buffer, size_t length, std::string* res)
{
	unsigned char keyBuf[AES_KEY_LENGTH];
	unsigned char iv[AES_KEY_LENGTH] = { 10, 4, 117, 110, 100, 11, 5, 11, 7, 36, 98, 25, 15, 11, 7, 10 };

	AES_KEY aesKey;
	int ret;

	unsigned int uiPaddingLen;
	unsigned int uiTotalLen;
	unsigned char* pData;

	memcpy(keyBuf, cKeyArr, AES_KEY_LENGTH);

	ret = AES_set_encrypt_key(keyBuf, 128, &aesKey);
	if (ret != 0) return false;

	uiPaddingLen = AES_KEY_LENGTH - (length % AES_KEY_LENGTH);
	uiTotalLen = length + uiPaddingLen;
	pData = (unsigned char*)malloc(uiTotalLen);
	memcpy(pData, buffer, length);

	if (uiPaddingLen > 0) memset(pData + length, uiPaddingLen, uiPaddingLen);

	res->clear();
	res->resize(uiTotalLen);

	AES_cbc_encrypt(pData, (unsigned char*)res->data(), uiTotalLen, &aesKey, iv, AES_ENCRYPT);

	free(pData);
	return true;
}

//AES解密pkcs#5填充
bool Utils::AESDecrypt(const char* pszKey, const char* buffer, size_t length, std::string* res)
{
	unsigned char keyBuf[AES_KEY_LENGTH];
	unsigned char iv[AES_KEY_LENGTH] = { 10, 4, 117, 110, 100, 11, 5, 11, 7, 36, 98, 25, 15, 11, 7, 10 };

	AES_KEY aesKey;
	int ret = 0;
	int uiPaddingLen = 0;
	memcpy(keyBuf, pszKey, AES_KEY_LENGTH);

	ret = AES_set_decrypt_key(keyBuf, 128, &aesKey);
	if (ret != 0) return false;

	res->clear();
	res->resize(length);

	AES_cbc_encrypt((unsigned char*)buffer, (unsigned char*)res->data(), length, &aesKey, iv, AES_DECRYPT);

	uiPaddingLen = (*res)[length - 1];
	if (uiPaddingLen > AES_KEY_LENGTH || uiPaddingLen < 0)
	{
		return false;
	}
	res->resize(length - uiPaddingLen);

	return true;
}

// 解密函数入口
bool Utils::Decode(const char* pszKey, const char* buffer, size_t length, std::string* res)
{
	std::string hex = Base64Decode(buffer, length);
	return AESDecrypt(pszKey, hex.c_str(), hex.length(), res);
}

// 加密函数入口
bool Utils::Encode(const char* pszKey, const char* buffer, size_t length, std::string* res)
{
	std::string temp_res;
	bool ret = AESEncrypt(pszKey, buffer, length, &temp_res);
	res->assign(Base64Encode(temp_res.c_str(), temp_res.length()));
	return ret;
}

bool Utils::Encode_2(unsigned char cKeyArr[16], const char* buffer, size_t length, std::string* res)
{
	std::string temp_res;
	bool ret = AESEncrypt_2(cKeyArr, buffer, length, &temp_res);
	res->assign(Base64Encode(temp_res.c_str(), temp_res.length()));
	return ret;
}

std::string Utils::MD5(const std::string& src)
{
	MD5_CTX ctx;

	std::string md5_string;
	unsigned char md[16] = { 0 };
	char tmp[33] = { 0 };

	MD5_Init(&ctx);
	MD5_Update(&ctx, src.c_str(), src.size());
	MD5_Final(md, &ctx);

	for (int i = 0; i < 16; ++i)
	{
		memset(tmp, 0x00, sizeof(tmp));
		sprintf(tmp, "%02x", md[i]);
		md5_string += tmp;
	}
	return md5_string;
}

void Utils::MD5_2(const std::string& src, unsigned char* md)
{
	MD5_CTX ctx;

	//std::string md5_string;
	//memset(md, 0, sizeof(md));
	//char tmp[33] = { 0 };

	MD5_Init(&ctx);
	MD5_Update(&ctx, src.c_str(), src.size());
	MD5_Final(md, &ctx);	
}

std::string Utils::StrToHex(const unsigned char* p, int iLen) 
{
	char psz[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
			'b', 'c', 'd', 'e', 'f' };
	char * pBuf = new char[iLen * 2 + 1];
	for (int i = 0; i < iLen; ++i) {
		pBuf[i * 2] = psz[(p[i] & 0xF0) >> 4];
		pBuf[i * 2 + 1] = psz[p[i] & 0xF];
	}
	pBuf[iLen * 2] = '\0';
	std::string ret = pBuf;
	delete[] pBuf;
	return ret;
}

void Utils::HexToStr(const unsigned char* pHex, unsigned int nHexLen,
	unsigned char* pBuf, unsigned int& nBufLen) 
{
	if ((NULL == pHex) || (0 == nHexLen))
		return;

	unsigned int nReadPos = 0;
	unsigned int nWritePos = 0;
	if (0 != (nHexLen % 2)) {
		if (isxdigit((unsigned char)pHex[nReadPos])) {
			pBuf[nWritePos++] = X2DIGITS_TO_NUM('0', pHex[nReadPos]);
		}
		nReadPos++;
	}
	while (nReadPos < nHexLen) {
		pBuf[nWritePos++] = X2DIGITS_TO_NUM(pHex[nReadPos],
			pHex[nReadPos + 1]);
		nReadPos += 2;
	}
	nBufLen = nWritePos;
}





